package com.imooc.miaosha.controller;

import com.imooc.miaosha.config.SeckillInitialization;
import com.imooc.miaosha.domian.MiaoShaOrder;
import com.imooc.miaosha.domian.OrderInfo;
import com.imooc.miaosha.domian.User;
import com.imooc.miaosha.rabbitmq.MiaoshaMessage;
import com.imooc.miaosha.rabbitmq.MqSender;
import com.imooc.miaosha.redis.RedisFactory;
import com.imooc.miaosha.redis.keys.GoodsKey;
import com.imooc.miaosha.redis.keys.MiaoshaKey;
import com.imooc.miaosha.redis.keys.OrderKey;
import com.imooc.miaosha.result.CodeMsg;
import com.imooc.miaosha.result.Result;
import com.imooc.miaosha.result.ResultEnums;
import com.imooc.miaosha.service.GoodsService;
import com.imooc.miaosha.service.MiaoShaService;
import com.imooc.miaosha.service.OrderService;
import com.imooc.miaosha.system.annotation.AccessLimit;
import com.imooc.miaosha.vo.GoodsVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

/**
 * 模块描述: <br>
 * (秒杀控制层)
 *
 * @Author: Mr. xyb
 * @Date: 2019/4/19 10:41
 * @since: 1.8.0
 * @version: 1.0.0
 */
@Controller
@RequestMapping("/miaosha")
public class MiaoShaController {

    /**
     * 重置各种数据
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/reset", method = RequestMethod.GET)
    @ResponseBody
    public Result<Boolean> reset(Model model) {
        List<GoodsVO> goodsList = goodsService.listGoodsVo();
        Map<Long, Boolean> localOver = seckillInitialization.localOver;
        for (GoodsVO goods : goodsList) {
            goods.setStockCount(10);
            redisFactory.set(GoodsKey.seckillGoodsStock, "" + goods.getId(), 10);
            localOver.put(goods.getId(), false);
        }
        redisFactory.delete(OrderKey.getMiaoshaOrderByUidGid);
        redisFactory.delete(MiaoshaKey.isGoodsOver);
        miaoShaService.reset(goodsList);
        return Result.success(true);
    }


    /**
     * 发起秒杀
     *
     * @param model
     * @param user
     * @param goodsId
     * @return
     */
    @PostMapping("/do_miaosha2")
    public String miaosha(Model model, User user, @RequestParam("goodsId") Long goodsId) {
        // 如果没登录，跳转到登录页
        if (user == null) {
            return "login";
        }
        // 查询库存
        GoodsVO goodsVo = goodsService.getGoodsVoByGoodsId(goodsId);
        if (goodsVo.getStockCount() <= 0) {
            model.addAttribute("errmsg", new CodeMsg(ResultEnums.MIAO_SHA_ENDING));
            return "miaosha_fail";
        }
        // 查询是否抢购过了
        MiaoShaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            model.addAttribute("errmsg", new CodeMsg(ResultEnums.REPREATE_MIAOSHA).getMsg());
            return "miaosha_fail";
        }

        // 秒杀下单
        OrderInfo orderInfo = miaoShaService.miaoSha(user, goodsVo);
        model.addAttribute("orderInfo", orderInfo);
        model.addAttribute("goods", goodsVo);
        return "order_detail";
    }


    /**
     * 发起秒杀（静态化）
     *
     * @param user
     * @param goodsId
     * @return
     */
    @PostMapping("/do_miaosha_static")
    @ResponseBody
    public Result<OrderInfo> miaoShaStatic(User user, @RequestParam("goodsId") Long goodsId) {
        // 如果没登录，跳转到登录页
        if (user == null) {
            return Result.error(ResultEnums.SESSION_ERROR);
        }

        // 查询库存
        GoodsVO goodsVo = goodsService.getGoodsVoByGoodsId(goodsId);
        if (goodsVo.getStockCount() <= 0) {
            return Result.error(ResultEnums.MIAO_SHA_ENDING);
        }

        // 查询是否抢购过了
        MiaoShaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            return Result.error(ResultEnums.REPREATE_MIAOSHA);
        }

        // 秒杀下单
        OrderInfo orderInfo = miaoShaService.miaoSha(user, goodsVo);
        return Result.success(orderInfo);
    }


    /**
     * 通过随机数以及验证码隐藏秒杀链接
     *
     * @param user
     * @param goodsId
     * @param verifyCode
     * @return
     */
    @AccessLimit(seconds=20, maxCount=5, needLogin=true)
    @RequestMapping(value = "/path")
    @ResponseBody
    public Result<String> getMiaoshaPath(User user,
                                         @RequestParam("goodsId") long goodsId,
                                         @RequestParam(value = "verifyCode", defaultValue = "0") int verifyCode) {
        if (user == null) {
            return Result.error(ResultEnums.SESSION_ERROR);
        }

        boolean check = miaoShaService.checkVerifyCode(user, goodsId, verifyCode);
        if (!check) {
            return Result.error(ResultEnums.VERIFY_CODE_FAIL);
        }
        String path = miaoShaService.createMiaoshaPath(user, goodsId);
        return Result.success(path);
    }


    /**
     * 秒杀链接，通过mq实现异步处理下单
     *
     * @param user
     * @param path
     * @param goodsId
     * @return
     */
    @PostMapping("/{path}/do_miaosha")
    @ResponseBody
    @AccessLimit(seconds = 50, maxCount = 5, needLogin = true)
    public Result<Integer> miaoShaMq(User user, @PathVariable("path") String path, @RequestParam("goodsId") Long goodsId) {
        // 如果没登录，跳转到登录页
        if (user == null) {
            return Result.error(ResultEnums.SESSION_ERROR);
        }

        boolean check = miaoShaService.checkPath(user, goodsId, path);
        if (!check) {
            return Result.error(ResultEnums.REQUEST_ILLEGAL);
        }

        Map<Long, Boolean> localOver = seckillInitialization.localOver;
        if (localOver.get(goodsId)) {
            return Result.error(ResultEnums.MIAO_SHA_ENDING);
        }

        // 预减库存
        Long stock = redisFactory.decr(GoodsKey.seckillGoodsStock, "" + goodsId);
        if (stock < 0) {
            localOver.put(goodsId, true);
            return Result.error(ResultEnums.MIAO_SHA_ENDING);
        }

        // 查询是否抢购过了
        MiaoShaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            return Result.error(ResultEnums.REPREATE_MIAOSHA);
        }

        MiaoshaMessage mm = new MiaoshaMessage();
        mm.setGoodsId(goodsId);
        mm.setUser(user);
        mqSender.sendMiaoshaMessage(mm);
        return Result.success(0);
    }

    /**
     * 轮询获取是否秒杀成功
     *
     * @param user
     * @param goodsId
     * @return
     */
    @GetMapping("/result")
    @ResponseBody
    public Result<Long> miaoshaResult(User user, @RequestParam("goodsId") long goodsId) {
        if (user == null) {
            return Result.error(ResultEnums.SESSION_ERROR);
        }
        long result = miaoShaService.getMiaoshaResult(user.getId(), goodsId);
        return Result.success(result);
    }

    /**
     * 获取验证码
     *
     * @param response
     * @param user
     * @param goodsId
     * @return
     */
    @RequestMapping(value = "/verifyCode", method = RequestMethod.GET)
    @ResponseBody
    public Result<String> getMiaoshaVerifyCod(HttpServletResponse response, User user,
                                              @RequestParam("goodsId") long goodsId) {
        if (user == null) {
            return Result.error(ResultEnums.SESSION_ERROR);
        }
        try {
            BufferedImage image = miaoShaService.createVerifyCode(user, goodsId);
            OutputStream out = response.getOutputStream();
            ImageIO.write(image, "JPEG", out);
            out.flush();
            out.close();
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(ResultEnums.MIAOSHA_FAIL);
        }
    }

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private MiaoShaService miaoShaService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private RedisFactory redisFactory;

    @Autowired
    private MqSender mqSender;

    @Autowired
    private SeckillInitialization seckillInitialization;

}
